import matplotlib as mpl
mpl.use("Agg")
mpl.rcParams['figure.figsize'] = (8, 6)
import pandas as pd
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import numpy as np
import datetime
from typing import List
import json


plt.rcParams['font.sans-serif']=['monospace', 'SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

DTML = List[datetime.datetime]


class FitResult(object):

    def __init__(self, dtm: DTML, ydata):
        assert len(dtm) == len(ydata), "length of dtm and ydata is not equal"
        self.dtm = dtm
        self.ydata = ydata

    @property
    def to_json(self):
        fdt = list()
        for i, e in enumerate(self.dtm):
            ctime = {
                'year': e.year,
                'month': e.month,
                'day': e.day,
                'hour': e.hour,
                'minute': e.minute,
                'second': e.second,
                'microsecond': e.microsecond
            }
            d = dict(fitValue=self.ydata[i],
                     datetime=ctime)
            fdt.append(d)
        return json.dumps(fdt)


def polynomial(xdata, *params):
    """
    计算多项式函数值
    :param xdata:
    :param params: 多项式系数,升幂排列
    :return:
    """
    n = len(params)
    y = params[0]
    for i in range(1, n):
        y += params[i] * np.power(xdata, i)
    return y


def polynomial1(xdata, a, b):
    return polynomial(xdata, a, b)


def polynomial2(xdata, a, b, c):
    return polynomial(xdata, a, b, c)


def polynomial3(xdata, a, b, c , d):
    return polynomial(xdata, a, b, c, d)


def polynomial4(xdata, a, b, c, d, e):
    return polynomial(xdata, a, b, c, d, e)


def polynomial5(xdata, a, b, c, d, e, f):
    return polynomial(xdata, a, b, c, d, e, f)


df = pd.read_json('http://localhost/main/all_data/')
time = df['datetime'][-72:]
percentage = df['percentage'][-72:]


def str2datetime(data):
    """

    :param data: "yyyy.mm.dd.hh.mm.ss.mmmmmm"
    :return: list
    """
    datatime_list = list()
    for i in data:
        temp = i.split('.')
        for k, v in enumerate(temp):
            temp[k] = int(v)
        datatime_list.append(datetime.datetime(*temp))

    return datatime_list


timedeltaList = List[datetime.timedelta]


def timedelta2total_seconds_batch(tdl: timedeltaList):
    """

    :param tdl:
    :return: secondsList
    """
    temp = list()
    for i in tdl:
        temp.append(i.total_seconds())
    return np.array(temp)


time = np.array(str2datetime(time))
START_TIME = time[0]


def func(x, a, b, c):
    return a * np.sin(-b * x) + c


# xdata = np.linspace(0, 4, 50)
# y = func(xdata, 2.5, 1.3, 0.5)
# np.random.seed(1729)
# y_noise = 0.2 * np.random.normal(size=xdata.size)
# ydata = y + y_noise


def fit():
    xdata = timedelta2total_seconds_batch(time - time[0])
    popt, pcov = curve_fit(polynomial5, xdata, percentage.to_numpy())
    ydata = polynomial5(xdata, *popt)

    fit_res = FitResult(time, ydata)
    return fit_res.to_json


def mul_fit():
    xdata = timedelta2total_seconds_batch(time - time[0])
    plt.plot(xdata, percentage, 'b-', label='data')

    popt, pcov = curve_fit(polynomial5, xdata, percentage.to_numpy())

    plt.plot(xdata, polynomial5(xdata, *popt), 'g--',
             label='5次多项式: a=%5.3f, b=%5.3f, c=%5.3f, d=%5.3f, e=%5.3f, f=%5.3f' % tuple(popt))

    popt, pcov = curve_fit(polynomial4, xdata, percentage.to_numpy())

    plt.plot(xdata, polynomial4(xdata, *popt), 'r.-',
             label='4次多项式: a=%5.3f, b=%5.3f, c=%5.3f, d=%5.3f, e=%5.3f' % tuple(popt))

    popt, pcov = curve_fit(polynomial3, xdata, percentage.to_numpy())

    plt.plot(xdata, polynomial3(xdata, *popt), 'r--',
             label='3次多项式: a=%5.3f, b=%5.3f, c=%5.3f, d=%5.3f' % tuple(popt))

    popt, pcov = curve_fit(polynomial2, xdata, percentage.to_numpy())

    plt.plot(xdata, polynomial2(xdata, *popt), 'x-',
             label='2次多项式: a=%5.3f, b=%5.3f, c=%5.3f' % tuple(popt))

    plt.xlabel('seconds')
    plt.ylabel('percentage')
    plt.legend()
    import os
    path = os.path.abspath('.')
    path = path + '/fit.png'
    plt.savefig(path)
    plt.close()
    return path


if __name__ == "__main__":
    mul_fit()
    plt.show()
